package com.nuvsoft.android.nuvgamenet.net;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.InetAddress;
import java.net.MulticastSocket;
import java.net.UnknownHostException;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;

import android.content.Context;
import android.net.wifi.WifiManager;
import android.net.wifi.WifiManager.MulticastLock;
import android.util.Log;

import com.nuvsoft.android.nuvgamenet.GameNetHelpers;
import com.nuvsoft.android.nuvgamenet.NuvGameNetApplication;

public class MulticastHandler {
	// private BuzzerApplication mContext;
	private List<MulticastListener> listeners;
	Thread myThread;
	private static MulticastSocket sendSocket, receiveSocket;
	private static final String LOG_TAG = MulticastHandler.class
			.getSimpleName();
	private static final String groupAddr = "235.1.1.2";
	private int BROADCAST_PORT;
	private int INCOMING_PORT = 47474;
	int MAX_MESSAGE_LENGTH = 1024;
	private static InetAddress group;
	private static WifiManager wm;
	private NuvGameNetApplication ba;
	private MulticastLock lock;

	public MulticastHandler(NuvGameNetApplication ba) {
		this.ba = ba;
		listeners = new CopyOnWriteArrayList<MulticastListener>();
		randomizeBroadcastPort();
	}

	public void closeSockets() {
		if (sendSocket != null) {
			sendSocket.close();
			sendSocket = null;
		}
		if (receiveSocket != null) {
			receiveSocket.close();
			receiveSocket = null;
		}
	}

	public void randomizeBroadcastPort() {
		Log.v(LOG_TAG, "RANDOMIZING PORTS!");
		do {
			BROADCAST_PORT = GameNetHelpers.getRandomPort();
		} while (BROADCAST_PORT == INCOMING_PORT);
	}

	public void getGroup() throws UnknownHostException {
		if (group == null) {
			group = InetAddress.getByName(groupAddr);
			// if(group.isMulticastAddress())
			// Log.v(LOG_TAG, "SWEET! MULTICAST BITCH!");
			// else
			// Log.v(LOG_TAG, "DAMN! NO MULTICAST!");
		}
	}

	public boolean sendData(String data) {
		try {
			Log.v(LOG_TAG, "ATTEMPTING TO SEND");
			getGroup();
			getSendSocket();
			DatagramPacket dataPckt = new DatagramPacket(data.getBytes(), data
					.length(), group, INCOMING_PORT);
			sendSocket.send(dataPckt);
			return true;
		} catch (Exception e) {
			Log.v(LOG_TAG, "FAILURE, RANDOMIZING PORT AND RETRYING.");
			closeSockets();
			randomizeBroadcastPort();
			e.printStackTrace();
			return false;
		}
	}

	public void getSendSocket() throws IOException {
		if (sendSocket == null) {
			sendSocket = new MulticastSocket();
			sendSocket.joinGroup(group);
			// sendSocket.setTimeToLive(1);
		}
	}

	public void getReceiveSocket() throws IOException {
		if (receiveSocket == null) {
			receiveSocket = new MulticastSocket(INCOMING_PORT);
			receiveSocket.setTimeToLive(1);
			// receiveSocket.setReuseAddress(true);
			receiveSocket.joinGroup(group);
		}
	}

	public void addBroadcastListener(MulticastListener l) {
		listeners.add(l);
	}

	public void getMulticastLock() {
		if (wm == null)
			wm = (WifiManager) ba.getSystemService(Context.WIFI_SERVICE);
		if (lock == null) {
			lock = wm.createMulticastLock("mylock");
			lock.setReferenceCounted(true);
		}
	}

	public void startListening() {
		try {
			getGroup();
			getReceiveSocket();
		} catch (Exception e2) {
			Thread.yield();
			startListening();
			e2.printStackTrace();
			return;
		}
		Runnable r = new Runnable() {
			public void run() {
				getMulticastLock();
				while (true) {
					try {
						while (true) {
							lock.acquire();
							byte[] buf = new byte[1024];
							DatagramPacket packet_r = new DatagramPacket(buf,
									buf.length);
							receiveSocket.receive(packet_r);
							String s = new String(packet_r.getData(), 0,
									packet_r.getLength());
							if (s.length() > 0) {
								for (MulticastListener l : listeners) {
									l.onReceiveBroadcast(s);
								}
							}
							Log.v(LOG_TAG, "Receiving a Multicast from ["
									+ packet_r.getAddress().getHostAddress()
									+ ":" + packet_r.getPort() + "]");
							Log.v(LOG_TAG, "Data: " + s);
							// CharSequence data = packet_r.getAddress()
							// .getHostAddress()
							// + ":" + packet_r.getPort();
							// Toast.makeText(view, data, Toast.LENGTH_SHORT)
							// .show();
							lock.release();
							Thread.yield();
						}
					} catch (IOException e) {
						Log.v(LOG_TAG, "UPNP network exception", e);
						try {
							Thread.sleep(1000);
						} catch (InterruptedException e1) {
							e.printStackTrace();
						}
					}
				}
			}
		};
		new Thread(r).start();
	}

	public void removeBroadcastListener(MulticastListener l) {
		listeners.remove(l);
	}
}